
#include <assert.h>
#include <gfx/idevice.h>
#include <gfx/iprogram.h>
#include <gfx/iprogramparameter.h>
#include <gfx/mesh.h>
#include <gfx/gl20/mesh/instancedmeshgpu.h>
#include <GL/glew.h>


ceInstancedMeshGPUGL20::ceInstancedMeshGPUGL20()
  : ceInstancedMeshGL20 ()
{
  CE_OBJECT_CONSTR
}

void ceInstancedMeshGPUGL20::Draw(const ceRenderEnvironment&, iDevice* device)
{
	if (_instanceUse <= 0)
    {
      return;
    }
  iProgram* prog = device->GetProgram();
  assert (prog);

  device->SetStreamSource(0, _mesh->GetVertices());
  device->SetIndices(_mesh->GetIndices());
  device->SetVertexDeclaration(_mesh->GetVertexDeclration());

  glDisable(GL_CULL_FACE);
  for (unsigned i=0; i<_instanceUse; i+=512)
    {
      unsigned n = _instanceUse - i;
      if (n > 512)
        {
          n = 512;
        }
			for (unsigned j=0, k=_instanceData.size (); j<k; j++)
				{
					ceInstancedData& d = _instanceData[j];
          iProgramParameter* pp = prog->GetParameter(d.Binding);
          if (!pp)
						{
							continue;
						}
					if (!d.Float)
						{
							// may not yet be initialised. so this is ok but must not be rendered.
							return;
						}

					switch (d.Type)
						{
						case IDT_Float:
              pp->Bind (n, &d.Float[i]);
							break;
						case IDT_Vector2:
              pp->Bind (n, &d.Vec2[i]);
							break;
						case IDT_Vector3:
              pp->Bind (n, &d.Vec3[i]);
							break;
						case IDT_Vector4:
              pp->Bind (n, &d.Vec4[i]);
							break;
						}
				}
      device->DrawIndexPrimitivesInstanced(PT_Triangles, _mesh->GetIndexDataType(), _mesh->GetNumberOfPrims(), n, true);
    }
  glEnable(GL_CULL_FACE);
}



